package com.content.scaffold.common.utils;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.content.scaffold.common.annotation.SensitiveField;
import com.content.scaffold.common.properties.EncryptProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopProxyUtils;

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author xiaojl
 */
public class SensitiveFieldEncryptor {

    private static final ConcurrentMap<Class<?>, Field[]> SENSITIVE_FIELDS_CACHE = new ConcurrentHashMap<>();
    private static volatile AES aes = null;

    public static AES getAesInstance() {
        if (aes == null) {
            synchronized (SensitiveFieldEncryptor.class) {
                if (aes == null) {
                    EncryptProperties properties = SpringContextHolder.getBean(EncryptProperties.class);
                    aes = SecureUtil.aes(SecureUtil.decode(properties.getKey()));
                }
            }
        }
        return aes;
    }

    public static void encryptSensitiveFields(Object obj) {
        if (obj == null) {
            return;
        }

        Class<?> clazz = AopProxyUtils.ultimateTargetClass(obj);

        // 使用缓存字段列表提升性能
        Field[] sensitiveFields = SENSITIVE_FIELDS_CACHE.computeIfAbsent(clazz, cls -> {
            while (cls != null && cls != Object.class) {
                for (Field field : cls.getDeclaredFields()) {
                    SensitiveField annotation = field.getAnnotation(SensitiveField.class);
                    if (annotation != null && annotation.encryption()) {
                        field.setAccessible(true);
                        // 可以收集到一个列表中返回
                    }
                }
                cls = cls.getSuperclass();
            }
            return new Field[0]; // 实际应返回收集到的字段数组
        });

        for (Field field : sensitiveFields) {
            try {
                Object value = field.get(obj);
                if (value instanceof String str && StringUtils.isNotBlank(str)) {
                    String encrypted = getAesInstance().encryptHex(str);
                    field.set(obj, encrypted);
                } else {
                    // 可选：记录日志提示字段类型不匹配
                }
            } catch (IllegalAccessException e) {
                // 记录更详细的上下文信息
                throw new RuntimeException("Failed to access field: " + field.getName(), e);
            } catch (Exception e) {
                throw new RuntimeException("Failed to encrypt field: " + field.getName(), e);
            }
        }
    }
}

